"""
Progress indication utilities for long-running CLI operations.

Provides progress bars, spinners, and status indicators for various
analysis and processing operations.
"""

import time
import threading
import sys
from typing import Optional, Callable, Any
from contextlib import contextmanager

from .colors import ColorPrinter, Color


class Spinner:
    """Animated spinner for indicating progress."""
    
    def __init__(self, message: str = "Processing...", spinner_chars: str = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"):
        self.message = message
        self.spinner_chars = spinner_chars
        self.is_spinning = False
        self.thread = None
        self.printer = ColorPrinter()
    
    def start(self):
        """Start the spinner animation."""
        if self.is_spinning:
            return
        
        self.is_spinning = True
        self.thread = threading.Thread(target=self._spin, daemon=True)
        self.thread.start()
    
    def stop(self, final_message: Optional[str] = None):
        """Stop the spinner animation."""
        if not self.is_spinning:
            return
        
        self.is_spinning = False
        if self.thread:
            self.thread.join()
        
        # Clear the spinner line and print final message
        self.printer.clear_line()
        if final_message:
            self.printer.print_success(final_message)
    
    def _spin(self):
        """Internal spinning animation."""
        i = 0
        while self.is_spinning:
            char = self.spinner_chars[i % len(self.spinner_chars)]
            self.printer.clear_line()
            self.printer.print_colored(f"{char} {self.message}", Color.CYAN, end='')
            sys.stdout.flush()
            time.sleep(0.1)
            i += 1
        
        # Clear line when done
        self.printer.clear_line()
    
    def __enter__(self):
        """Context manager entry."""
        self.start()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """Context manager exit."""
        if exc_type is None:
            self.stop("Done")
        else:
            self.stop("Failed")


class ProgressBar:
    """Progress bar for operations with known duration."""
    
    def __init__(self, total: int, message: str = "Progress", width: int = 40):
        self.total = total
        self.current = 0
        self.message = message
        self.width = width
        self.start_time = time.time()
        self.printer = ColorPrinter()
    
    def update(self, increment: int = 1, message: Optional[str] = None):
        """Update progress by increment amount."""
        self.current = min(self.current + increment, self.total)
        if message:
            self.message = message
        self._draw()
    
    def set_progress(self, current: int, message: Optional[str] = None):
        """Set absolute progress value."""
        self.current = min(max(current, 0), self.total)
        if message:
            self.message = message
        self._draw()
    
    def finish(self, message: Optional[str] = None):
        """Complete the progress bar."""
        self.current = self.total
        if message:
            self.message = message
        self._draw()
        print()  # Move to next line
    
    def _draw(self):
        """Draw the progress bar."""
        if self.total == 0:
            percentage = 100
        else:
            percentage = (self.current / self.total) * 100
        
        # Calculate filled portion
        filled = int((percentage / 100) * self.width)
        bar = "█" * filled + "░" * (self.width - filled)
        
        # Calculate ETA
        elapsed = time.time() - self.start_time
        if self.current > 0 and self.current < self.total:
            eta = (elapsed / self.current) * (self.total - self.current)
            eta_str = f" ETA: {eta:.1f}s"
        else:
            eta_str = ""
        
        # Format display
        progress_text = f"{self.message} [{bar}] {self.current}/{self.total} ({percentage:.1f}%){eta_str}"
        
        # Clear line and print progress
        self.printer.clear_line()
        self.printer.print_colored(progress_text, Color.CYAN, end='')
        sys.stdout.flush()


class MultiStepProgress:
    """Progress indicator for multi-step operations."""
    
    def __init__(self, steps: list, message_prefix: str = "Step"):
        self.steps = steps
        self.current_step = 0
        self.message_prefix = message_prefix
        self.printer = ColorPrinter()
        self.start_time = time.time()
    
    def start_step(self, step_name: Optional[str] = None):
        """Start the next step."""
        if step_name is None and self.current_step < len(self.steps):
            step_name = self.steps[self.current_step]
        
        self.current_step += 1
        step_text = f"{self.message_prefix} {self.current_step}/{len(self.steps)}: {step_name}"
        self.printer.print_info(step_text)
    
    def complete_step(self, message: Optional[str] = None):
        """Complete current step."""
        if message:
            self.printer.print_success(f"  ✓ {message}")
        else:
            self.printer.print_success("  ✓ Completed")
    
    def fail_step(self, error_message: str):
        """Mark current step as failed."""
        self.printer.print_error(f"  ✗ {error_message}")
    
    def finish(self):
        """Complete all steps."""
        elapsed = time.time() - self.start_time
        self.printer.print_success(f"All steps completed in {elapsed:.2f}s")


class StatusIndicator:
    """Simple status indicator for quick operations."""
    
    def __init__(self):
        self.printer = ColorPrinter()
    
    def show_status(self, message: str, status: str = "info"):
        """Show status message with appropriate icon."""
        if status == "success":
            self.printer.print_success(message)
        elif status == "error":
            self.printer.print_error(message)
        elif status == "warning":
            self.printer.print_warning(message)
        elif status == "progress":
            self.printer.print_progress(message)
        else:
            self.printer.print_info(message)
    
    @contextmanager
    def operation(self, message: str, success_message: str = "Done", error_message: str = "Failed"):
        """Context manager for operations with start/end status."""
        self.printer.print_progress(f"{message}...")
        try:
            yield
            self.printer.print_success(success_message)
        except Exception as e:
            self.printer.print_error(f"{error_message}: {e}")
            raise


class ProgressIndicator:
    """Main progress indicator class that combines all progress types."""
    
    def __init__(self):
        self.printer = ColorPrinter()
    
    def spinner(self, message: str = "Processing...") -> Spinner:
        """Create a spinner progress indicator."""
        return Spinner(message)
    
    def progress_bar(self, total: int, message: str = "Progress") -> ProgressBar:
        """Create a progress bar."""
        return ProgressBar(total, message)
    
    def multi_step(self, steps: list, prefix: str = "Step") -> MultiStepProgress:
        """Create a multi-step progress indicator."""
        return MultiStepProgress(steps, prefix)
    
    def status(self) -> StatusIndicator:
        """Create a status indicator."""
        return StatusIndicator()
    
    @contextmanager
    def timed_operation(self, message: str):
        """Context manager that times an operation."""
        start_time = time.time()
        self.printer.print_progress(f"Starting: {message}")
        
        try:
            yield
            elapsed = time.time() - start_time
            self.printer.print_success(f"Completed: {message} ({elapsed:.2f}s)")
        except Exception as e:
            elapsed = time.time() - start_time
            self.printer.print_error(f"Failed: {message} after {elapsed:.2f}s - {e}")
            raise
    
    @contextmanager
    def file_operation(self, file_path: str, operation: str = "Processing"):
        """Context manager for file operations."""
        self.printer.print_progress(f"{operation} {file_path}")
        
        try:
            yield
            self.printer.print_success(f"✓ {operation} completed for {file_path}")
        except Exception as e:
            self.printer.print_error(f"✗ {operation} failed for {file_path}: {e}")
            raise
    
    def show_analysis_progress(self, current_file: str, current_function: str, 
                             files_processed: int, total_files: int):
        """Show progress for analysis operations."""
        percentage = (files_processed / total_files) * 100 if total_files > 0 else 0
        
        status_line = (
            f"Analyzing {current_function} in {current_file} "
            f"({files_processed}/{total_files} files, {percentage:.1f}%)"
        )
        
        self.printer.clear_line()
        self.printer.print_colored(status_line, Color.CYAN, end='')
        sys.stdout.flush()
    
    def show_tree_building_progress(self, current_node: str, total_nodes: int, depth: int):
        """Show progress for call tree building."""
        status_line = f"Building call tree: {current_node} (nodes: {total_nodes}, depth: {depth})"
        
        self.printer.clear_line()
        self.printer.print_colored(status_line, Color.CYAN, end='')
        sys.stdout.flush()
    
    def clear_progress(self):
        """Clear any active progress indicators."""
        self.printer.clear_line()
    
    def print_completion_summary(self, operation: str, duration: float, 
                               items_processed: int, errors: int = 0):
        """Print operation completion summary."""
        print()  # New line after progress
        
        self.printer.print_header("Operation Complete", level=2)
        
        summary = {
            "Operation": operation,
            "Duration": f"{duration:.2f} seconds",
            "Items Processed": items_processed,
            "Success Rate": f"{((items_processed - errors) / items_processed * 100):.1f}%" if items_processed > 0 else "N/A"
        }
        
        if errors > 0:
            summary["Errors"] = errors
        
        for key, value in summary.items():
            self.printer.print_key_value(key, value)
        
        if errors == 0:
            self.printer.print_success("Operation completed successfully!")
        else:
            self.printer.print_warning(f"Operation completed with {errors} errors")


# Convenience functions for common patterns

@contextmanager
def spinner_context(message: str = "Processing..."):
    """Convenience context manager for spinner."""
    with Spinner(message) as spinner:
        yield spinner


@contextmanager
def progress_context(total: int, message: str = "Progress"):
    """Convenience context manager for progress bar."""
    progress = ProgressBar(total, message)
    try:
        yield progress
    finally:
        progress.finish()


def with_progress(func: Callable) -> Callable:
    """Decorator to add progress indication to functions."""
    def wrapper(*args, **kwargs):
        func_name = func.__name__.replace("_", " ").title()
        
        with spinner_context(f"Executing {func_name}"):
            return func(*args, **kwargs)
    
    return wrapper